package io.kiki.sba.registry.remoting.netty;


import io.kiki.sba.registry.api.ChannelConnectException;
import io.kiki.sba.registry.api.ChannelHandler;
import io.kiki.sba.registry.api.ChannelOverflowException;
import io.kiki.sba.registry.api.exchange.RequestChannelClosedException;
import io.kiki.sba.registry.api.exchange.RequestException;
import io.kiki.sba.registry.util.StringFormatter;
import io.kiki.stack.netty.exception.RemotingException;

import java.util.List;


public final class BoltUtil {
    private BoltUtil() {
    }

    public static Byte getBoltCustomSerializer(io.kiki.sba.registry.api.Channel channel) {
        if (channel instanceof Channel) {

            // set client custom codec for request command if not null
            Object clientCustomCodec = null;//boltChannel.getConnAttribute(RequestContext.BOLT_CUSTOM_SERIALIZER);
            if (null != clientCustomCodec) {
                try {
                    return (Byte) clientCustomCodec;
                } catch (ClassCastException e) {
                    throw new IllegalArgumentException("Illegal custom codec [" + clientCustomCodec + "], the type of value should be [byte], but now is [" + clientCustomCodec.getClass().getName() + "].");
                }
            }
        }
        return null;
    }

    public static RuntimeException handleException(String role, Object target, Throwable e, String op) {
        if (e instanceof RemotingException) {
            final String format = StringFormatter.format("{} {} RemotingException! target url:{}", role, op, target);
            final String msg = e.getMessage();
            // see RpcClientRemoting.connectionManager.check
            if (msg != null) {
                if (msg.contains("write overflow")) {
                    return new ChannelOverflowException(format, e);
                }
                if (msg.contains("Connection is null when do check") || msg.contains("Check connection failed for address")) {
                    return new ChannelConnectException(format, e);
                }
            }
            return new RuntimeException(format, e);
        }
        if (e instanceof InterruptedException) {
            String msg = StringFormatter.format("{} {} InterruptedException! target url:{}", role, op, target);
            return new RuntimeException(msg, e);
        }
        String msg = StringFormatter.format("{} {} Exception! target url:{}", role, op, target);
        return new RuntimeException(msg, e);
    }

    public static void checkChannelConnected(io.kiki.sba.registry.api.Channel channel) {
        if (channel == null) {
            throw new RequestException("channel is null");
        }
        if (!channel.isConnected()) {
            throw new RequestChannelClosedException("channel is not connect:" + channel);
        }
    }

    public static io.kiki.stack.netty.channelManager.Url createTargetUrl(io.kiki.sba.registry.api.Channel channel) {
        return new io.kiki.stack.netty.channelManager.Url(channel.getRemoteAddress().getAddress().getHostAddress(), channel.getRemoteAddress().getPort());
    }

    public static ChannelHandler getListenerHandlers(List<ChannelHandler> channelHandlers) {
        ChannelHandler connectionEventHandler = null;
        for (ChannelHandler channelHandler : channelHandlers) {
            if (ChannelHandler.HandlerType.LISTENER.equals(channelHandler.getHandlerType())) {
                if (connectionEventHandler != null) {
                    throw new IllegalArgumentException(StringFormatter.format("only support one listener handler, {} conflict {}", connectionEventHandler, channelHandler));
                }
                connectionEventHandler = channelHandler;
            }
        }
        return connectionEventHandler;
    }
}
